package util;

import com.google.common.collect.Maps;
import domain.User;
import org.apache.ibatis.annotations.Select;

import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.lang.reflect.Proxy;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
 * JDK动态代理
 */

interface UserMapper{
    @Select("select * from user where id = #{id} and name = #{username}")
    List<User> selectUserList(Integer id,String username);
}

public class JdkProxy {
    public static void main(String[] args) {
        //返回的Object对象就是代理对象
        UserMapper userMapper = (UserMapper) Proxy.newProxyInstance(JdkProxy.class.getClassLoader(), new Class<?>[]{UserMapper.class}, (proxy, method, args1) -> {
            System.out.println(method.getName());
            //获取方法上的Select注解
            Select annotation = method.getAnnotation(Select.class);
            if(annotation!=null){
                String[] value = annotation.value();
                System.out.println(Arrays.asList(value));   //[select * from user where id = #{id}]
                //获取参数(设置：Java Complier——>Additional command line parameters:-parameters )
                System.out.println(Arrays.toString(args1));
                Map<String, Object> argNameMap = buildMethodArgNameMap(method, args1);
                System.out.println(argNameMap);
                String parseSQL = parseSQL(value[0], argNameMap);
                System.out.println(parseSQL);
                System.out.println(method.getReturnType());
                System.out.println(method.getGenericReturnType());
            }

            return null;
        });
        userMapper.selectUserList(1,"hangman");
    }
    //构建请求参数Map
    public static Map<String,Object> buildMethodArgNameMap(Method method, Object[] args){
        Map<String, Object> argNameMap = Maps.newHashMap();   //大数据量parallelStream()并行处理
        Parameter[] parameters = method.getParameters();
        final int[] index = {0};
        Arrays.asList(parameters).forEach(parameter -> {
            argNameMap.put(parameter.getName(),args[index[0]]);
            index[0]++;
        });
        return argNameMap;
    }

    //解析sql
    public static String parseSQL(String sql,Map<String, Object> argNameMap){
        StringBuilder stringBuilder = new StringBuilder();
        int length = sql.length();

        for (int i = 0; i < length; i++) {
            char c = sql.charAt(i);
            if(c == '#'){
                int nextIndex = i + 1;
                char nextChar = sql.charAt(nextIndex);
                if(nextChar != '{'){
                    throw new RuntimeException(String.format("这里应该为#{\nsql:%s\nindex:%d",stringBuilder.toString(),nextIndex));
                }
                //解析#{}里的内容
                StringBuilder argSB = new StringBuilder();
                i = parseSQLArg(argSB,sql,nextIndex);
                String argName = argSB.toString();
                Object argValue = argNameMap.get(argName);
                if(argValue == null){
                    throw new RuntimeException(String.format("找不到参数值:%s",argName));
                }
                stringBuilder.append(argValue.toString());
                continue;
            }
            stringBuilder.append(c);
        }
        return stringBuilder.toString();
    }

    private static int parseSQLArg(StringBuilder argSB, String sql, int nextIndex) {
        nextIndex++;
        for (; nextIndex < sql.length(); nextIndex++) {
            char c = sql.charAt(nextIndex);
            if(c != '}'){
                argSB.append(c);
                continue;
            }
            return nextIndex;
        }
        throw new RuntimeException(String.format("缺少右括号\nindex:%d",nextIndex));
    }
}
